package jfae.core.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Filter è l'annotazione principale per la generazione
 * dinamica dei form di editing e dei filtri di ricerca 
 * per l'entity (ma qualunque bean java va bene).
 * @author bobpuley
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Filterable {

	/**
	 * Default value per {@link #groupNames()}
	 */
	public static final String NO_GROUP_SET = "no_group";
	
	/**
	 * Default value per {@link #order()}
	 */
	public static final int DEFAULT_ORDER = Integer.MAX_VALUE;

	/**
	 * default value per il gruppo di filtri usato nella lookup {@link #groupNames()}
	 */
	public static final String LOOKUP_GROUP = "lookup_group";

	/**
	 * Posizione nella lista dei filtri
	 * @return {@link Integer#MAX_VALUE} se non è impostato
	 */
	int order() default DEFAULT_ORDER;
	
	/*
	 * Simmetrico a {@link #searchProperty()} permette di
	 * specificare i nomi delle proprietà dell'entity collegato
	 * Poniamo di avere due classi:
	 * <code>
	 * <pre>
	 * class A{
	 * 		&#64;Filter private String prop1;
	 * 		&#64;Filter private String prop2;
	 * </pre>
	 * </code>
	 * ....
	 * <code>
	 * <pre>
	 * }
	 * </pre>
	 * <code>
	 * e
	 * <code>
	 * <pre>
	 * class B{
	 * 		private A propA;
	 * 		private String propString;
	 * 		&#64;Filterable(searchProperties={"prop1", "prop2"})
	 * 		public A getPropA(){
	 * 			return propA;
	 * 		}
	 * 		&#64;Filter
	 * 		public String getPropString(){
	 * 			return propString;
	 * 		}
	 * }
	 * </pre>
	 * <code>
	 * In questo modo, qunado verrà creato il filter per <code>B</code>,
	 * il sistema aggiungerà due filtri basati su A.prop1 e A.prop2.
	 * Otterremmo quindi:
	 * <ul>
	 * 	<li>propA.prop1</li>
	 * 	<li>propA.prop2</li>
	 * 	<li>propString</li>
	 * </ul>
	 * Questo attributo ha senso solo nel caso in cui si annoti una proprietà
	 * che sia a sua volta un entity.
	 * @return le proprietà della inner class
	 */
	String[] searchProperties() default {};
	
	/**
	 * Questo attributo viene usato per specificare che una proprietà va usata dai
	 * <i>parent object</i> come filtro.
	 * In altre parole se avessimo:
	 * <code>
	 * <pre>
	 * class A{
	 * 		&#64;Filter(searchProperty=true) private String prop1;
	 * 		&#64;Filter(searchProperty=true) private String prop2;
	 * </pre>
	 * </code>
	 * ....
	 * <code>
	 * <pre>
	 * }
	 * </pre>
	 * <code>
	 * e
	 * <code>
	 * <pre>
	 * class B{
	 * 		private A propA;
	 * 		private String propString;
	 * 		&#64;Filter(searchProperties={"prop1", "prop2"})
	 * 		public A getPropA(){
	 * 			return propA;
	 * 		}
	 * 		&#64;Filter
	 * 		public String getPropString(){
	 * 			return propString;
	 * 		}
	 * }
	 * </pre>
	 * <code>
	 * In questo modo, qunado verrà creato il filter per <code>B</code>,
	 * il sistema aggiungerà due filtri basati su A.prop1 e A.prop2.
	 * Otterremmo quindi:
	 * <ul>
	 * 	<li>propA.prop1</li>
	 * 	<li>propA.prop2</li>
	 * 	<li>propString</li>
	 * </ul>
	 * 
	 * @return true se è una proprietà da mostrare nella enclosing class
	 */
	boolean searchProperty() default false;

	/*
	 * Permette di specificare le direttive di presentazione
	 * dentro l'annotation stessa. Tuttavia è possibile
	 * anche agganciare {@link Presentation} direttamente al metodo
	 * @return le regole di presentazione
	 */
//	Presentation presentation() default @Presentation;
	
	/**
	 * Contiene i nomi dei gruppi in cui può comparire
	 * il filtro. Per default vale {@link #NO_GROUP_SET} 
	 * @return un'array di String con i nomi settati oppure
	 * {{@value #NO_GROUP_SET}}
	 */
	String[] groupNames() default {NO_GROUP_SET};
	
}
